import base64

import pickle
from django.shortcuts import render
from django_redis import get_redis_connection
from redis import StrictRedis
from rest_framework import status
from rest_framework.generics import GenericAPIView
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView

from cart import constants
from cart.serializer import CartSerializer, CartShowSerializer, CartDeleteSerializer
from goods.models import SKU


class CartView(GenericAPIView):
    """购物车"""
    serializer_class = CartSerializer

    # 跳过ＤＲＦ认证
    def perform_authentication(self, request):
        pass

    def post(self, request):
        # 接受参数并校验
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)

        # 校验过的数据
        sku_id = serializer.validated_data['sku_id']
        count = serializer.validated_data['count']
        selected = serializer.validated_data['selected']

        # 保存用户购物车记录
        try:
            user = request.user
        except Exception:
            user = None

        if user and user.is_authenticated:
            # 登录用户
            # 存入redis数据库中
            conn = get_redis_connection('cart')
            key = 'cart_%s' % user.id
            selected_key = 'selected_%s' % user.id
            # 判断该商品是否已经存在于购物车中
            # cart_1:{
            #     2: 3,
            #     3: 5
            # }
            conn.hincrby(key, sku_id, count)  # 为键累加值，不存在的话，就新建
            if selected:
                conn.sadd(selected_key, sku_id)
            return Response(serializer.validated_data)

        else:
            # 未登录用户
            # 存入cookie中
            cart_data = request.COOKIES.get('cart')

            if cart_data:
                cart_dict = pickle.loads(base64.b64decode(cart_data))

                # cookie中存在购物车数据
                # {
                #     sku_id: {
                #         'count':数量,
                #         'selected': True
                #     }
                # }
            else:
                cart_dict = {}

            if sku_id in cart_dict:
                cookie_count = cart_dict[sku_id]['count']
                count += cookie_count

            cart_dict[sku_id] = {
                'count': count,
                'selected': selected
            }
            # 设置cookie,保存到本地
            response = Response(serializer.validated_data)
            res_data = base64.b64encode(pickle.dumps(cart_dict)).decode()

            response.set_cookie('cart', res_data, max_age=constants.CART_COOKIE_EXPIRES)

            # 返回响应
            return response

    def get(self, request):
        """购物车信息获取"""
        try:
            user = request.user
        except Exception:
            user = None

        if user and user.is_authenticated:
            # 用户已登陆
            # 从redis中获取数量和sku信息
            key = 'cart_%s' % user.id
            conn = get_redis_connection('cart')
            # 获取sku数量信息
            cart_sku = conn.hgetall(key)

            # bytes类型
            # cart_2:{
            #     sku_id: count,
            #     ...
            # }

            # 获取选中的sku
            selected_key = 'selected_%s' % user.id
            cart_selected = conn.smembers(selected_key)
            # bytes类型
            # (sku_id.....)

            cart_dict = {}
            # 将数据构建为和cookie中的一样,以便同时处理
            for sku_id, count in cart_sku.items():
                cart_dict[int(sku_id)] = {
                    'count': int(count),
                    'selected': sku_id in cart_selected
                }

        else:
            # 用户未登录,从cookie中获取
            cookie_cart = request.COOKIES.get('cart')
            if cookie_cart:
                # 解析数据
                cart_dict = pickle.loads(base64.b64decode(cookie_cart))
                # {
                #     sku_id:{
                #         'count': count,
                #         'selected': True/False
                #     }
                # }

            else:
                cart_dict = {}

        # 获取所有商品信息
        sku_ids = cart_dict.keys()
        skus = SKU.objects.filter(id__in=sku_ids)
        for sku in skus:
            sku.count = cart_dict[sku.id]['count']
            sku.selected = cart_dict[sku.id]['selected']

        # 序列化输出
        serializer = CartShowSerializer(skus, many=True)
        return Response(serializer.data)

    def put(self, request):
        """购物车信息修改"""
        # 接收数据并校验
        serializer = CartSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)

        # 获取校验后数据
        sku_id = serializer.validated_data['sku_id']
        count = serializer.validated_data['count']
        selected = serializer.validated_data['selected']

        # 获取登陆用户用户
        try:
            user = request.user
        except Exception:
            user = None

        if user and user.is_authenticated:
            # 用户登录
            # 修改redis中用户数据
            key = 'cart_%s' % user.id
            conn = get_redis_connection('cart')
            conn.hset(key, sku_id, count)

            set_key = 'selected_%s' % user.id
            if selected:
                # 选中了,加入到set中
                conn.sadd(set_key, sku_id)
            else:
                # 未选中,从set中移除
                conn.srem(set_key, sku_id)
            return Response(serializer.data)

        else:
            # 用户未登录
            response = Response(serializer.data)
            cookie_cart = request.COOKIES.get('cart')
            if cookie_cart:
                cart_dict = pickle.loads(base64.b64decode(cookie_cart))
                # {
                #     sku_id: {
                #         'count': count,
                #         'selected': selected
                #     }
                # }
            else:
                return response
            if not sku_id in cart_dict:
                return response

            cart_dict[sku_id]['count'] = count
            cart_dict[sku_id]['selected'] = selected

            # 重新设置cookie
            cart_data = base64.b64encode(pickle.dumps(cart_dict)).decode()
            response.set_cookie('cart', cart_data, max_age=constants.CART_COOKIE_EXPIRES)

            # 返回相应
            return response

    def delete(self, request):
        """购物车记录删除"""
        serializer = CartDeleteSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)

        # 获取用户
        try:
            user = request.user
        except Exception:
            user = None
        # 获取校验后数据
        sku_id = serializer.validated_data['sku_id']

        if user and user.is_authenticated:
            # 用户登陆
            # 删除对应数据
            conn = get_redis_connection('cart')  # type:StrictRedis
            key = 'cart_%s' % user.id
            conn.hdel(key, sku_id)
            # 删除set中记录
            selected_key = 'selected_%s' % user.id
            conn.srem(selected_key, sku_id)
            return Response({'message': 'OK'})
        else:
            response = Response({'message': 'OK'})
            # 用户未登录
            cookie_cart = request.COOKIES.get('cart')
            if cookie_cart is None:
                return response
            # 解析数据
            cookie_dict = pickle.loads(base64.b64decode(cookie_cart))

            # {
            #     'sku_id': {
            #         'count': count,
            #         'selected': selected
            #     }
            # }
            if not cookie_dict:
                return response
            if not sku_id in cookie_dict:
                return response
            del cookie_dict[sku_id]
            # 重新设置cookie中数据
            cookie_data = base64.b64encode(pickle.dumps(cookie_dict)).decode()  # str
            response.set_cookie('cart', cookie_data, max_age=constants.CART_COOKIE_EXPIRES)
            return response


class CartSelectOrCancelAll(APIView):
    """商品全选全不选"""

    # 跳过ＤＲＦ认证
    def perform_authentication(self, request):
        pass

    def put(self, request):
        selected = request.data.get('selected')
        print(selected)
        # if not selected:
        #     return Response({'message': '参数错误'}, status=status.HTTP_400_BAD_REQUEST)

        # 获取用户
        try:
            user = request.user
        except Exception:
            user = None
        if user and user.is_authenticated:
            # 用户登陆
            conn = get_redis_connection('cart')
            key = 'cart_%s' % user.id
            sku_ids = conn.hkeys(key)
            selected_key = 'selected_%s' % user.id
            if selected:
                # 全选
                conn.sadd(selected_key, *sku_ids)
            else:
                # 全不选
                conn.srem(selected_key, *sku_ids)
        else:
            # 用户未登录
            response = Response({'message': 'OK'})
            cookie_cart = request.COOKIES.get('cart')
            if cookie_cart is None:
                return response
            # 解析数据
            cookie_dict = pickle.loads(base64.b64decode(cookie_cart))

            # {
            #     'sku_id': {
            #         'count': count,
            #         'selected': selected
            #     }
            # }
            if not cookie_dict:
                return response
            sku_ids = cookie_dict.keys()
            skus = SKU.objects.filter(id__in=sku_ids)
            for sku in skus:
                cookie_dict[sku.id]['selected'] = selected
            # 重新设置cookie中数据
            cookie_data = base64.b64encode(pickle.dumps(cookie_dict)).decode()  # str
            response.set_cookie('cart', cookie_data, max_age=constants.CART_COOKIE_EXPIRES)
            return response
